package cn.lyjuan.first.netty.demo._1_nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class NIOServer
{
    private ServerSocketChannel serverChannel;

    private Selector selector;

    private NIOServer()
    {
    }

    public static NIOServer init(int port) throws IOException
    {
        NIOServer server = new NIOServer();
        // 配置channel
        server.serverChannel = ServerSocketChannel.open();
        server.serverChannel.configureBlocking(false);
        server.serverChannel.socket().bind(new InetSocketAddress(port));

        // 注册selector处理事件
        server.selector = Selector.open();
        server.serverChannel.register(server.selector, SelectionKey.OP_ACCEPT);

        return server;
    }

    public void listener() throws IOException
    {
        System.out.println("server listener");
        while (true)
        {
            // 阻塞方式获取待处理事件
            int count = this.selector.select();
            if (count < 1) continue;

            // 遍历事件
            Iterator<SelectionKey> it = this.selector.selectedKeys().iterator();
            while (it.hasNext())
            {
                SelectionKey key = it.next();
                it.remove();
                if (key.isAcceptable())// 接受连接
                    accept(key);
                else if (key.isReadable())// 读取
                    read(key);
            }
        }
    }

    /**
     * 接受连接
     *
     * @param key
     */
    private void accept(SelectionKey key) throws IOException
    {
        ServerSocketChannel channel = (ServerSocketChannel) key.channel();
        SocketChannel client = channel.accept();
        if (null == client) return;

        InetSocketAddress remote = (InetSocketAddress) client.getRemoteAddress();
        System.out.println("accept client: " + remote.getHostString() + ":" + remote.getPort());

        // 设置成非阻塞
        client.configureBlocking(false);

        // 注册读取事件
        client.register(this.selector, SelectionKey.OP_READ);
    }

    /**
     * 读取
     *
     * @param key
     */
    private void read(SelectionKey key) throws IOException
    {
        SocketChannel client = (SocketChannel) key.channel();
        if (null == client) return;

        // 读取
        ByteBuffer buf = ByteBuffer.allocate(1024);
        int count = client.read(buf);
        if (count < 0)
        {
            key.cancel();
            return;
        }

        String result = new String(buf.array(), 0, count);
        System.out.println("read: " + result);
        if ("byte".equalsIgnoreCase(result))// 断开连接
        {
            if (client.isOpen())
                client.close();
            key.cancel();
            return;
        }

        // 回写
        ByteBuffer outBuf = ByteBuffer.wrap("World".getBytes("UTF-8"));
        client.write(outBuf);
    }

    public static void main(String[] args) throws IOException
    {
        NIOServer server = NIOServer.init(8000);
        server.listener();
    }
}
